[XEN] Fix interaction between tlbflush timestamp and shadow flags
authorTim Deegan <tim.deegan@xensource.com>
Thu, 28 Sep 2006 16:09:11 +0000 (17:09 +0100)
committerTim Deegan <tim.deegan@xensource.com>
Thu, 28 Sep 2006 16:09:11 +0000 (17:09 +0100)
Signed-off-by: Tim Deegan <Tim.Deegan@xensource.com>
xen/arch/x86/mm.c
xen/arch/x86/mm/shadow/common.c
xen/include/asm-x86/shadow.h

index 8b09e26f8f5b6e70424f03829fdd27d1af8d6125..d7041c7af1f3c5c5509512316a54f99d208f6d9a 100644 (file)
@@ -1544,9 +1544,7 @@ void free_page_type(struct page_info *page, unsigned long type)
 
             gmfn = mfn_to_gmfn(owner, page_to_mfn(page));
             ASSERT(VALID_M2P(gmfn));
-            shadow_lock(owner);
             shadow_remove_all_shadows(owner->vcpu[0], _mfn(gmfn));
-            shadow_unlock(owner);
         }
     }
 
@@ -1618,8 +1616,8 @@ void put_page_type(struct page_info *page)
              *  2. Shadow mode reuses this field for shadowed page tables to
              *     store flags info -- we don't want to conflict with that.
              */
-            if ( !shadow_mode_enabled(page_get_owner(page)) ||
-                 ((nx & PGT_type_mask) == PGT_writable_page) )
+            if ( !(shadow_mode_enabled(page_get_owner(page)) &&
+                   (page->count_info & PGC_page_table)) )
                 page->tlbflush_timestamp = tlbflush_current_time();
         }
     }
@@ -1644,6 +1642,12 @@ int get_page_type(struct page_info *page, unsigned long type)
         }
         else if ( unlikely((x & PGT_count_mask) == 0) )
         {
+            struct domain *d = page_get_owner(page);
+
+            /* Never allow a shadowed frame to go from type count 0 to 1 */
+            if ( d && shadow_mode_enabled(d) )
+                shadow_remove_all_shadows(d->vcpu[0], _mfn(page_to_mfn(page)));
+
             ASSERT(!(x & PGT_pae_xen_l2));
             if ( (x & PGT_type_mask) != type )
             {
@@ -1652,8 +1656,9 @@ int get_page_type(struct page_info *page, unsigned long type)
                  * may be unnecessary (e.g., page was GDT/LDT) but those 
                  * circumstances should be very rare.
                  */
-                cpumask_t mask =
-                    page_get_owner(page)->domain_dirty_cpumask;
+                cpumask_t mask = d->domain_dirty_cpumask;
+
+                /* Don't flush if the timestamp is old enough */
                 tlbflush_filter(mask, page->tlbflush_timestamp);
 
                 if ( unlikely(!cpus_empty(mask)) &&
index fa530c06ca52cc65259b658e1d61ba2761f8f5d8..f2fafe117647319bb640c931814381a0ebbb8f33 100644 (file)
@@ -256,7 +256,11 @@ void shadow_demote(struct vcpu *v, mfn_t gmfn, u32 type)
     clear_bit(type >> PGC_SH_type_shift, &page->shadow_flags);
 
     if ( (page->shadow_flags & SHF_page_type_mask) == 0 )
+    {
+        /* tlbflush timestamp field is valid again */
+        page->tlbflush_timestamp = tlbflush_current_time();
         clear_bit(_PGC_page_table, &page->count_info);
+    }
 }
 
 /**************************************************************************/
index 94a4ff11fd51f6b658855eb99add88d1040c08e9..d6c9688de718fab7f5cac7a23251a74a4fe52d96 100644 (file)
@@ -481,7 +481,12 @@ shadow_remove_all_shadows_and_parents(struct vcpu *v, mfn_t gmfn);
 extern void sh_remove_shadows(struct vcpu *v, mfn_t gmfn, int all);
 static inline void shadow_remove_all_shadows(struct vcpu *v, mfn_t gmfn)
 {
+    int was_locked = shadow_lock_is_acquired(v->domain);
+    if ( !was_locked )
+        shadow_lock(v->domain);
     sh_remove_shadows(v, gmfn, 1);
+    if ( !was_locked )
+        shadow_unlock(v->domain);
 }
 
 /* Add a page to a domain */